/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: Optional.h
 *
 * Purpose: This section describes the class template ara::core::Optional that
 *          provides access to Optional record elements of a Structure 
 *          Implementation data type.
 *          Whenever there is a mention of the standard C++17 item std::Optional, 
 *          the implied source material is[n4695.pdf,23.6]
 *          The class template ara::core::Optional manages Optional values, 
 *          i.e. values that may or may not be present. The existence can be 
 *          evaluated during both compile-time and runtime
 *
 * Developer:
 *   wen.gu , 2020-04-14
 *
 * TODO:
 *
 ***************************************************************************/

#ifndef __ARA_CORE_Optional_H__
#define __ARA_CORE_Optional_H__
/******************************************************************************
 **    INCLUDES
 ******************************************************************************/

#include <type_traits>

#include "ara/core/utility.h"

/******************************************************************************
 **    MACROS
 ******************************************************************************/


/******************************************************************************
 **    TYPE DEFINITIONS
 ******************************************************************************/
namespace ara
{
namespace core
{
/******************************************************************************
 **    CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/
template <class T>
class Optional;

/// no-value state indicator.
struct nullopt_t
{
    // Do not user-declare default constructor at all for
    // Optional_value = {} syntax to work.
    // nullopt_t() = delete;

    // Used for constructing nullopt.
    enum class _Construct { _Token };

    // Must be constexpr for nullopt_t to be literal.
    explicit constexpr nullopt_t(_Construct) { }
};

#if __cplusplus > 201402L  /** only C++17 or more can use this syntax */
/// Tag to disengage Optional objects.
inline constexpr nullopt_t nullopt{ nullopt_t::_Construct::_Token };
#else
constexpr nullopt_t nullopt{ nullopt_t::_Construct::_Token };
#endif


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
template <class T>
class Optional {

public:
    using value_type = T;

    /** EI: enable_if */
    template<typename Ty>
    using EI_IsCopyConstructible = typename std::enable_if< std::is_copy_constructible<Ty>::value >::type;

    template<typename Ty>
    using EI_IsMoveConstructible = typename std::enable_if< std::is_move_constructible<Ty>::value >::type;

    template<typename Ty, typename... Args>
    using EI_IsConstructible = typename std::enable_if< std::is_constructible<Ty, Args...>::value >::type;

    /**for rhs construct with a value(not Optional<T>&&, just U&& ) */

    template<typename U>
    using EI_ForRhsUConstructExplicit = typename std::enable_if<  
                                        !std::is_convertible<U&&, T>::value &&
                                        std::is_constructible<T, U&& >::value &&
                                        !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
                                        !std::is_same<Optional<T>, typename std::decay<U>::type>::value, bool>::type;


    template<typename U>
    using EI_ForRhsUConstruct = typename std::enable_if<
                                        std::is_constructible<T, U&&>::value &&
                                        !std::is_same<typename std::decay<U>::type, in_place_t>::value &&
                                        !std::is_same<Optional<T>, typename std::decay<U>::type>::value &&
                                        std::is_convertible<U&&, T>::value, bool >::type;

    template<typename U>
    using EI_ForLhsConstructExplicit = typename std::enable_if <
                                        std::is_constructible<T, const U&>::value &&
                                        !std::is_constructible<T, Optional<U>&>::value &&
                                        !std::is_constructible<T, Optional<U>&&>::value &&
                                        !std::is_constructible<T, const Optional<U>&>::value &&
                                        !std::is_constructible<T, const Optional<U>&&>::value &&
                                        !std::is_convertible<Optional<U>&, T>::value &&
                                        !std::is_convertible<Optional<U>&&, T>::value &&
                                        !std::is_convertible<const Optional<U>&, T>::value &&
                                        !std::is_convertible<const Optional<U>&&, T>::value &&
                                        !std::is_convertible<const U&, T>::value, bool>::type;
                                                

    template<typename U>
    using EI_ForLhsConstruct = typename std::enable_if <
                                        std::is_constructible<T, const U&>::value &&
                                        !std::is_constructible<T, Optional<U>&>::value &&
                                        !std::is_constructible<T, Optional<U>&&>::value &&
                                        !std::is_constructible<T, const Optional<U>&>::value &&
                                        !std::is_constructible<T, const Optional<U>&&>::value &&
                                        !std::is_convertible<Optional<U>&, T>::value &&
                                        !std::is_convertible<Optional<U>&&, T>::value &&
                                        !std::is_convertible<const Optional<U>&, T>::value &&
                                        !std::is_convertible<const Optional<U>&&, T>::value &&
                                        std::is_convertible<const U&, T>::value, bool>::type;

    template <typename U>
    using EI_ForRhsConstructExplicit = typename std::enable_if <
                                                std::is_constructible<T, U&&>::value&&
                                                !std::is_constructible<T, Optional<U>&>::value &&
                                                !std::is_constructible<T, Optional<U>&&>::value &&
                                                !std::is_constructible<T, const Optional<U>&>::value &&
                                                !std::is_constructible<T, const Optional<U>&&>::value &&
                                                !std::is_convertible<Optional<U>&, T>::value &&
                                                !std::is_convertible<Optional<U>&&, T>::value &&
                                                !std::is_convertible<const Optional<U>&, T>::value &&
                                                !std::is_convertible<const Optional<U>&&, T>::value &&
                                                !std::is_convertible<U&&, T>::value, bool>::type;


    template <typename U>
    using EI_ForRhsConstruct = typename std::enable_if <
                                        std::is_constructible<T, U&&>::value &&
                                        !std::is_constructible<T, Optional<U>&>::value &&
                                        !std::is_constructible<T, Optional<U>&&>::value &&
                                        !std::is_constructible<T, const Optional<U>&>::value &&
                                        !std::is_constructible<T, const Optional<U>&&>::value &&
                                        !std::is_convertible<Optional<U>&, T>::value &&
                                        !std::is_convertible<Optional<U>&&, T>::value &&
                                        !std::is_convertible<const Optional<U>&, T>::value &&
                                        !std::is_convertible<const Optional<U>&&, T>::value &&
                                        std::is_convertible<U&&, T>::value, bool>::type;

    template <typename U>
    using EI_ForRhsUAssign = typename std::enable_if<
                                     !std::is_same<Optional<T>, typename std::decay<U>::type >::value &&
                                     !Conjunction<std::is_scalar<T>, std::is_same<T, typename std::decay<U>::type >>::value &&
                                     std::is_constructible<T, U>::value &&
                                     std::is_assignable<T&, U>::value, bool >::type;


    template <typename U>
    using EI_ForRhsAssign = typename std::enable_if<
                                     std::is_constructible<T, const U&>::value &&
                                     std::is_assignable<T&, const U&>::value &&
                                     !std::is_constructible<T, Optional<U>&>::value &&
                                     !std::is_constructible<T, Optional<U>&&>::value &&
                                     !std::is_constructible<T, const Optional<U>&>::value &&
                                     !std::is_constructible<T, const Optional<U>&&>::value &&
                                     !std::is_convertible<Optional<U>&, T>::value &&
                                     !std::is_convertible<Optional<U>&&, T>::value &&
                                     !std::is_convertible<const Optional<U>&, T>::value &&
                                     !std::is_convertible<const Optional<U>&&, T>::value &&
                                     !std::is_assignable<T&, Optional<U>&>::value &&
                                     !std::is_assignable<T&, Optional<U>&&>::value &&
                                     !std::is_assignable<T&, const Optional<U>&>::value &&
                                     !std::is_assignable<T&, const Optional<U>&&>::value, bool>::type;



    template <typename U>
    using EI_ForRhsAssign2 = typename std::enable_if<
                                      std::is_constructible<T, U>::value &&
                                      std::is_assignable<T&, U>::value &&
                                      !std::is_constructible<T, Optional<U>&>::value &&
                                      !std::is_constructible<T, Optional<U>&&>::value &&
                                      !std::is_constructible<T, const Optional<U>&>::value &&
                                      !std::is_constructible<T, const Optional<U>&&>::value &&
                                      !std::is_convertible<Optional<U>&, T>::value &&
                                      !std::is_convertible<Optional<U>&&, T>::value &&
                                      !std::is_convertible<const Optional<U>&, T>::value &&
                                      !std::is_convertible<const Optional<U>&&, T>::value &&
                                      !std::is_assignable<T&, Optional<U>&>::value &&
                                      !std::is_assignable<T&, Optional<U>&&>::value &&
                                      !std::is_assignable<T&, const Optional<U>&>::value &&
                                      !std::is_assignable<T&, const Optional<U>&&>::value, bool>::type;

    template<typename U, typename ...Args>
    using EI_ForEmplace = typename std::enable_if<std::is_constructible<T, Args&&...>::value >::type;

    template<typename U>
    using EI_ForSwap = typename std::enable_if< std::is_move_constructible<T>::value
#if cplusplus >= 201703L  /** only >= c++17, have template is_swappable */
    && std::is_swappable<U>::value
#endif
    >::type;

    template <typename U>
    using EI_ForValueOr = typename std::enable_if< 
                                std::is_copy_constructible<T>::value && 
                                std::is_convertible<U&&, T>::value >::type;

    template <typename U>
    using EI_ForValueOr2 = typename std::enable_if<
                                    std::is_move_constructible<T>::value &&
                                    std::is_convertible<U&&, T>::value >::type;

public:
    // 23.6.3.1, constructors
    constexpr Optional() noexcept
        :mVal(nullptr)
    {
        /** todo something */
    }

    constexpr Optional(nullopt_t) noexcept
        :mVal(nullptr)
    {

    }
    template<class = EI_IsCopyConstructible<T> >
    constexpr Optional(const Optional& other)
        :Optional()
    {
        if (other.mVal)
        {
            mVal = new value_type(*(other.mVal));
        }
    }

    template<class = EI_IsMoveConstructible<T> >
    constexpr Optional(Optional&& other) noexcept(std::is_nothrow_move_constructible<T>::value)
        :Optional()
    {
        mVal = other.mVal;
        other.mVal = nullptr;
    }

    template <class... Args, class = EI_IsConstructible<T, Args&&...> >
    constexpr explicit Optional(in_place_t, Args&&... args)
        :mVal(new value_type(std::forward<Args>(args)...))
    {
        /** todo something */    
    }

    template <class U, 
              class... Args, 
              class = EI_IsConstructible<T, std::initializer_list<U>&, Args&&...> >
    constexpr explicit Optional(in_place_t, std::initializer_list<U> il, Args&&... args)
        :mVal(new value_type(il, std::forward<Args>(args)...))
    {
        /** todo something */
    }

    template <class U = T, EI_ForRhsUConstruct<U> = true >
    constexpr Optional(U&& v)
        :mVal(new value_type(std::forward<U>(v)))
    {
        /** todo something */
    }

    template <class U = T, EI_ForRhsUConstructExplicit<U> = false >
     explicit constexpr  Optional(U&& v)
        :mVal(new value_type(std::forward<U>(v)))
    {
        /** todo something */
    }


    template <class U, EI_ForLhsConstructExplicit<U> = false >
    explicit Optional(const Optional<U>& other)
        :Optional()
    {
        if (other.mVal)
        {
            mVal = new T(*other.mVal);
        }
    }
 
    template <class U, EI_ForLhsConstruct<U> = true >
    Optional(const Optional<U>& other)
        :Optional()
    {
        if (other.mVal)
        {
            mVal = new T(*other.mVal);
        }
    }


    template <class U, EI_ForRhsConstructExplicit<U> = false >
    explicit Optional(Optional<U>&& other)
        :Optional()
    {
        if (other.mVal)
        {
            mVal = new value_type(std::move(*other.mVal));
        }
    }

    template <class U, EI_ForRhsConstruct<U> = true >
    Optional(Optional<U>&& other)
        :Optional()
    {
        if (other.mVal)
        {
            mVal = new value_type(std::move(*other.mVal));
        }
    }
    
    // 23.6.3.2, destructor
    ~Optional()
    {
        if (mVal)
        {
            if (std::is_trivially_destructible<T>::value)
            {
                delete mVal;
            }
            else
            {
                mVal->T::~T();  /** todo, is this right?? */
            }           
        }
    }
public:

    // 23.6.3.3, assignment
    Optional& operator=(nullopt_t) noexcept
    {
        if (mVal)
        {
            delete mVal; /** todo, is need mVal->T::~T() */
            mVal = nullptr; 
        }

        return *this;
    }

    Optional& operator=(const Optional& rhs)
    {
        if (rhs.mVal)
        {
            if (mVal)
            {
                *mVal = *rhs.mVal;
            }
            else
            {
                mVal = new value_type(*rhs.mVal);
            }
        }
        else
        {
            *this = nullopt;
        }

        return *this;
    }

    Optional& operator=(Optional&& rhs) noexcept(std::is_nothrow_move_assignable<T>::value &&
                                             std::is_nothrow_move_constructible<T>::value)
    {
        if (rhs.mVal)
        {
            if (mVal)
            {
                *mVal = std::move(*rhs.mVal);
            }
            else
            {
                mVal = new value_type(std::move(*rhs.mVal));
            }
        }
        else
        {
            *this = nullopt;
        }

        return *this;
    }

    template <class U = T, EI_ForRhsUAssign<U> = true>
    Optional& operator=(U&& v)
    {
        if (mVal)
        {
            *mVal = std::forward<U>(v);
        }
        else
        {
            mVal = new value_type(std::forward<U>(v));
        }

        return *this;
    }

    template <class U, EI_ForRhsAssign<U> = true>
    Optional& operator=(const Optional<U>& rhs)
    {
        if (rhs.mVal)
        {
            if (mVal)
            {
                *mVal = *rhs.mVal;
            }
            else
            {
                mVal = new value_type(*rhs.mVal);
            }
        }
        else
        {
            *this = nullopt;
        }

        return *this;
    }


    template <class U, EI_ForRhsAssign2<U> = true>
    Optional& operator=(Optional<U>&& rhs)
    {
        if (rhs.mVal)
        {
            if (mVal)
            {
                *mVal = std::move(*rhs.mVal);
            }
            else
            {
                mVal = new value_type(std::move(*rhs.mVal));
            }
        }
        else
        {
            *this = nullopt;
        }

        return *this;
    }

    template <class... Args, class= EI_ForEmplace<T, Args...> >
    T& emplace(Args&&... args)
    {
        *this = nullopt;
        mVal = new value_type(std::forward<Args>(args)...);

        return *mVal;
    }

    template <class U, class... Args, class=EI_ForEmplace<T, std::initializer_list<U>&, Args&&... >>
    T& emplace(std::initializer_list<U> il, Args&&... args)
    {
        *this = nullopt;
        mVal = new value_type(il, std::forward<Args>(args)...);

        return *mVal;
    }

    // 23.6.3.4, swap
    template<class = EI_ForSwap<T> >
    void swap(Optional& rhs) noexcept(std::is_nothrow_move_constructible<T>::value 
#if  __cplusplus >= 201703L  /** only >= c++17, have template is_nothrow_swappable */
    && std::is_nothrow_swappable<T>::value
#endif //  __cplusplus >= 201703L
    )
    {
        if (rhs.mVal)
        {
            if (mVal)
            {
                swap(*(*this), *rhs);
            }
            else
            {
                mVal = new value_type(std::move(*rhs.mVal));
                rhs = nullopt;
            }
        }
        else
        {
            if (mVal)
            {
                rhs.mVal = new value_type(std::move(*mVal));
                *this = nullopt;
            }
        }
    }

public:
    // 23.6.3.5, observers
    constexpr const T* operator->() const
    {
        return mVal;
    }

    constexpr T* operator->()
    {
        return mVal;
    }

    constexpr const T& operator*() const&
    {
        return *mVal; /** todo, refine me?? */
    }

    constexpr T& operator*()&
    {
        return *mVal; /** todo, refine me?? */
    }

    constexpr T&& operator*()&&
    {
        return std::move(*mVal);
    }

    constexpr const T&& operator*() const&&
    {
        return std::move(*mVal);
    }

    constexpr explicit operator bool() const noexcept
    {
        return mVal != nullptr;
    }

    constexpr bool has_value() const noexcept
    {
        return mVal != nullptr;
    }

    /**
     *[SWS_CORE_01030] [DRAFT] value member function overloads [Contrary
     * to the description in [n4695.pdf,23.6], no member functions with 
     * this name exist in ara::core::Optional.]
     */
#if 0
    constexpr const T& value() const&;
    constexpr T& value()&;
    constexpr T&& value()&&;
    constexpr const T&& value() const&&;
#endif /** todo, is this right? */

    template <class U, class = EI_ForValueOr<U> >
    constexpr T value_or(U&& v) const&
    {
         return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));
    }

    template <class U, class = EI_ForValueOr2<U> > 
    constexpr T value_or(U&& v )&&
    {
        return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));
    }

    // 23.6.3.6, modifiers
    void reset() noexcept
    {
        *this = nullopt;
    }
private:
    value_type* mVal; // exposition only
};



///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//relational operators
template <class T, class U>
constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (bool(lhs) == bool(rhs))
    {
        return (bool(lhs) == false) ? true : (*lhs == *rhs);
    }

    return false;
}

template <class T, class U>
constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (bool(lhs) == bool(rhs))
    {
        return (bool(lhs) == false) ? false : (*lhs == *rhs);
    }

    return true;
}

template <class T, class U>
constexpr bool operator<(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (rhs)
    {
        return !lhs ? true : (*lhs < *rhs);
    }

    return false;
}

template <class T, class U>
constexpr bool operator>(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (lhs)
    {
        return !rhs ? true : (*lhs > *rhs);
    }

    return false;
}

template <class T, class U>
constexpr bool operator<=(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (lhs)
    {
        return !rhs ? false : (*lhs <= * rhs);
    }

    return true;
}

template <class T, class U>
constexpr bool operator>=(const Optional<T>& lhs, const Optional<U>& rhs)
{
    if (rhs)
    {
        return !lhs ? false : (*lhs >= *rhs);
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//comparison with nullopt
template <class T> 
constexpr bool operator==(const Optional<T>& x, nullopt_t) noexcept
{
    return !x;
}

template <class T> 
constexpr bool operator==(nullopt_t, const Optional<T>& x) noexcept
{
    return !x;
}

template <class T> 
constexpr bool operator!=(const Optional<T>& x, nullopt_t) noexcept
{
    return bool(x);
}

template <class T> 
constexpr bool operator!=(nullopt_t, const Optional<T>& x) noexcept
{
    return bool(x);
}

template <class T> 
constexpr bool operator<(const Optional<T>& x, nullopt_t) noexcept
{
    return false;
}

template <class T> 
constexpr bool operator<(nullopt_t, const Optional<T>& x) noexcept
{
    return bool(x);
}

template <class T> 
constexpr bool operator<=(const Optional<T>& x, nullopt_t) noexcept
{
    return !x;
}

template <class T> 
constexpr bool operator<=(nullopt_t, const Optional<T>& x) noexcept
{
    return true;
}

template <class T> 
constexpr bool operator>(const Optional<T>& x, nullopt_t) noexcept
{
    return bool(x);
}

template <class T> 
constexpr bool operator>(nullopt_t, const Optional<T>& x) noexcept
{
    return false;
}

template <class T> 
constexpr bool operator>=(const Optional<T>& x, nullopt_t) noexcept
{
    return true;
}

template <class T> 
constexpr bool operator>=(nullopt_t, const Optional<T>& x) noexcept
{
    return !x;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//comparison with T
template <class T, class U> 
constexpr bool operator==(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x == v : false;
}

template <class T, class U> 
constexpr bool operator==(const U& v, const Optional<T>& x)
{
    return bool(x) ? v == *x : false;
}

template <class T, class U> 
constexpr bool operator!=(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x != v : true;
}

template <class T, class U> 
constexpr bool operator!=(const U& v, const Optional<T>& x)
{
    return bool(x) ? v != *x : true;
}

template <class T, class U> 
constexpr bool operator<(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x < v : true;
}

template <class T, class U> 
constexpr bool operator<(const U& v, const Optional<T>& x)
{
    return bool(x) ? v < *x : false;
}

template <class T, class U> 
constexpr bool operator<=(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x <= v : true;
}

template <class T, class U> 
constexpr bool operator<=(const U& v, const Optional<T>& x)
{
    return bool(x) ? v <= *x : false;
}

template <class T, class U> 
constexpr bool operator>(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x > v : false;
}

template <class T, class U> 
constexpr bool operator>(const U& v, const Optional<T>& x)
{
    return bool(x) ? v > * x : true;
}

template <class T, class U> 
constexpr bool operator>=(const Optional<T>& x, const U& v)
{
    return bool(x) ? *x >= v : false;
}

template <class T, class U> 
constexpr bool operator>=(const U& v, const Optional<T>& x)
{
    return bool(x) ? v >= *x : true;
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//specialized algorithms
template <class T, class= typename std::enable_if<std::is_move_constructible<T>::value
#if  __cplusplus >= 201703L  /** only >= c++17, have template is_swappable_v */
    && std::is_swappable_v<T>
#endif
>::type >
void swap(Optional<T>& x, Optional<T>& y) noexcept(noexcept(x.swap(y)))
{
    x.swap(y);
}

template <class T>
constexpr Optional<typename std::decay<T>::type > make_Optional(T&& v)
{
    return Optional<std::decay<T>::type>(std::forward<T>(v));
}


template <class T, class... Args>
constexpr Optional<T> make_Optional(Args&&... args)
{
    return Optional<T>(in_place, std::forward<Args>(args)...);
}

template <class T, class U, class... Args>
constexpr Optional<T> make_Optional(std::initializer_list<U> il, Args&&... args)
{
    return Optional<T>(in_place, il, std::forward<Args>(args)...);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//hash support
template <class T> struct hash;
template <class T> struct hash<Optional<T>>
{
    std::size_t operator()(const Optional<T>& o) const
    {
        if (bool(o))
            return std::hash<T>()(*o);
        return 0;
    }
};

} /** namespace core */
} /** namespace ara */

#endif /** !__ARA_CORE_Optional_H__ */

